#include "elog.h"

/* elog object */
static elog_t g_elog;

/* level output info */
static const char *level_output_info[] = {
        "A",
        "E",
        "W",
        "I",
        "D",
        "V",
};

/**
 * elog initialize.
 *
 * @return result
 */
int elog_init(char *logname) {
    elog_t  *elog = NULL;
    int     i;
    char    logName[SIZE+9+4+1];//9位日期(__20160918) 4位(.log)
    char    date[DTIME_LEN + 1];

    memset(logName, 0x00, sizeof(logName));
    memset(date, 0x00, sizeof(date));

    snprintf(logName, SIZE, "%s", logname);
    if(strlen(logName) <= 0){
        snprintf(logName, SIZE, LOGNAME_DEFAULT);
    }
    if( elog_get_datetime(date, DTIME_LEN) < 0){
        return -1;
    }
    strtok(date, "|");
    snprintf(logName+strlen(logName), 9+4+1, "_%s.log", date);
//    printf("debug 1 logName = [%s]\n", logName);
    elog = getrlog();
    elog->fd = NULL;
    elog->std = dup(STDOUT_FILENO);
    elog->loglevel = ELOG_LVL_VERBOSE;
    for (i = 0; i < ELOG_LVL_TOTAL_NUM; ++i){
        elog->fmt_set[i] = ELOG_FMT_ALL;
    }
    elog->output_enabled = true;
//    elog->mutex = PTHREAD_MUTEX_INITIALIZER;
//    pthread_mutex_init(&(elog->mutex), NULL);
    if((elog->fd = fopen(logName, "a+")) == NULL){
        fprintf(stderr, "error redirecting stdout! errno = [%d][%s]\n", errno, strerror(errno));
        return (-1);
    }
    dup2(fileno(elog->fd), STDOUT_FILENO);
    elog_write(ELOG_LVL_ASSERT, "", "=================================== BEGIN ======================================");

    return 0;
}
/**
 * lock output
 */
void elog_output_lock(void) {
     elog_t *elog = getrlog();
     pthread_mutex_lock(&(elog->mutex));
}
/**
 * unlock output and fflush
 */
void elog_output_unlock(void) {
    elog_t *elog = getrlog();
    pthread_mutex_unlock(&(elog->mutex));

}
void elog_fflush(void){
	elog_t *elog = getrlog();
    fflush(elog->fd);
}
/**
 * set output enable or disable
 *
 * @param enabled TRUE: enable FALSE: disable
 */
void elog_set_output_enabled(bool enabled) {
	elog_t *elog = getrlog();
    if((enabled != false) && (enabled != true)){
        return;
    }
    elog_output_lock();
    elog->output_enabled = enabled;
    elog_output_unlock();
}

/**
 * get output is enable or disable
 *
 * @return enable or disable
 */
bool elog_get_output_enabled(void) {
	elog_t *elog = getrlog();
    return elog->output_enabled;
}
/**
 * set log output format. only enable or disable
 *
 * @param level level
 * @param set format set
 */
void elog_set_fmt(int level, size_t set) {
	elog_t *elog = getrlog();
    if(level > ELOG_LVL_VERBOSE || level < 0){
        return ;
    }

    elog->fmt_set[level] = set;
}
/**
 * get format enabled
 *
 * @param level level
 * @param set format set
 *
 * @return enable or disable
 */
bool elog_get_fmt_enabled(int level, size_t set) {
elog_t* elog = getrlog();
    if(level > ELOG_LVL_VERBOSE || level < 0){
        return false;
    }
    if (elog->fmt_set[level] & set) {
        return true;
    } else {
        return false;
    }
}
/**
 * set log output format. only enable or disable
 *
 * @param level level
 * @param set format set
 */
void elog_set_level(int level){
    elog_t *elog = getrlog();
    if(level > ELOG_LVL_VERBOSE || level < 0){
        return;
    }

    elog->loglevel = level;
}
void elog_set_output(int out, const char* newfile){
    elog_t *elog = getrlog();
    char    logName[SIZE+9+4+1];//9位日期(__20160918) 4位(.log)
    char    date[DTIME_LEN+1];
    FILE *newfd = NULL;

    memset(logName, 0x00, sizeof(logName));
    memset(date, 0x00, sizeof(date));

    if(newfile != NULL){
        snprintf(logName, SIZE, "%s", newfile);
        if(strlen(logName) <= 0){
            snprintf(logName, SIZE, LOGNAME_DEFAULT);
        }
        if( elog_get_datetime(date, DTIME_LEN) < 0){
            return;
        }
        strtok(date, "|");
        snprintf(logName+strlen(logName), 9+4+1, "_%s.log", date);
        if((newfd = fopen(logName, "a+")) == NULL){
            elog_write(ELOG_LVL_ASSERT, "", "error redirecting stdout! errno = [%d][%s]\n", errno, strerror(errno));
            return;
        }else{
        	elog->fd = newfd;
        	newfd = NULL;
        }
        dup2(fileno(elog->fd), STDOUT_FILENO);
    }else{
        if(out == ELOG_OUT_STDOUT){
            dup2(elog->std, STDOUT_FILENO);//stdout
        }else if(out == ELOG_OUT_FILE){
            dup2(fileno(elog->fd), STDOUT_FILENO);//file
        }
    }
}
int elog_get_datetime(char *dtime, int len)
{
        struct timeb tz;
        struct tm    *p = NULL;

        if(dtime == NULL || len < DTIME_LEN )
        {
            return -2;
        }
        memset(dtime, 0x00, len);

        ftime(&tz);
        p = localtime(&(tz.time));

        sprintf(dtime,"%02d%02d%02d|%02d:%02d:%02d.%03d",1900+p->tm_year, 1+p->tm_mon, p->tm_mday, p->tm_hour, p->tm_min, p->tm_sec, tz.millitm);

        return 0;
}
/**
 * output the log
 *
 * @param level level
 * @param tag tag
 * @param file file name
 * @param func function name
 * @param line line number
 * @param format output format
 * @param ... args
 *
 */
bool elog_output(int level, const char *tag, const char *file, const char *func, const long line) {
    elog_t *elog = getrlog();
    int log_len = 0;
    char dtime[DTIME_LEN+1];

    memset(dtime, 0x00, sizeof(dtime));

    if(level > ELOG_LVL_VERBOSE || level < 0){
        return false;
    }

    /* check output enabled */
    if (!(elog->output_enabled)) {
        return false;
    }
    /* level */
    if (level > elog->loglevel) {
        return false;
    }
    elog_print("@");
    /* package process info */
    if (elog_get_fmt_enabled(level, ELOG_FMT_P_INFO)) {
        elog_print("%d|", getpid());
    }
    /* package thread info */
    if (elog_get_fmt_enabled(level, ELOG_FMT_T_INFO)) {
        elog_print("%d|", gettid());
    }
    /* package time info */
    if (elog_get_fmt_enabled(level, ELOG_FMT_TIME)) {
        elog_get_datetime(dtime, DTIME_LEN);
        elog_print("%s|", dtime);
    }

    /* package level info */
    if (elog_get_fmt_enabled(level, ELOG_FMT_LVL)) {
        elog_print("%s|", level_output_info[level]);
    }
    /* package tag info */
    if (elog_get_fmt_enabled(level, ELOG_FMT_TAG)) {
        elog_print("%s ", tag);
    }
    if(elog_get_fmt_enabled(level, ELOG_FMT_FILE)) {
        elog_print("%s:", file);
    }
    if(elog_get_fmt_enabled(level, ELOG_FMT_FUNC)) {
        elog_print("%s:", func);
    }
    if(elog_get_fmt_enabled(level, ELOG_FMT_LINE)) {
        elog_print("%ld ", line);
    }
    return true;
}

void elog_release(){
    elog_t *elog = getrlog();
    elog_write(ELOG_LVL_ASSERT, "", "=================================== END ======================================");
    fclose(elog->fd);
    close(elog->std);
}

